//////////////////////////////////////////////////////////////////////
//
// NO_Utils.h
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
#ifndef NO_UTILS_H
#define NO_UTILS_H

//////////////////////////////////////////////////////////////////////////
#include <algorithm>

//////////////////////////////////////////////////////////////////////////
// type manipulation
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
template<class Src, class Dest>
Dest noForceCast(Src src)
{
	union
	{
		Dest d;
		Src s;
	} convertor;

	convertor.s = src;
	return convertor.d;
}

//////////////////////////////////////////////////////////////////////////
struct noStartOfObjectHelper
{
	template<typename U>
	static void* dynamicCastToVoid(U* p)
	{
		try{return dynamic_cast<void*>(p);}
		catch(...){throw std::bad_cast();}
		return static_cast<void*>(p);
	}
};

//////////////////////////////////////////////////////////////////////////
template<typename T>
void* noStartOfObject(T* p)
{
	void* q=static_cast<void*>(p);
	try{if(p){typeid(q=noStartOfObjectHelper::dynamicCastToVoid(p),*p);}}
	catch(...){throw std::bad_cast();}
	
	return q;
}

//////////////////////////////////////////////////////////////////////////
// binary type select
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
template <bool>
struct NO_SelectImpl
{
	template <class T, class U>
		struct In
	{
		typedef T Result;
	};
};

//////////////////////////////////////////////////////////////////////////
template <>
struct NO_SelectImpl<false>
{
	template <class T, class U>
		struct In
	{
		typedef U Result;
	};
};

//////////////////////////////////////////////////////////////////////////
template <bool flag, typename T, typename U>
struct NO_TypeSelect
{
	typedef typename NO_SelectImpl<flag>::template In<T, U>::Result Result;
};

//////////////////////////////////////////////////////////////////////////
//is_reference
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
typedef char yes_type;
struct no_type {char padding[8];};
template <class T> struct wrap {};

//////////////////////////////////////////////////////////////////////////
template <class T> T&(* is_reference_helper1(wrap<T>) )(wrap<T>);
no_type is_reference_helper1(...);

//////////////////////////////////////////////////////////////////////////
template <class T> no_type is_reference_helper2(T&(*)(wrap<T>));
yes_type is_reference_helper2(...);

//////////////////////////////////////////////////////////////////////////
template <typename T>
struct is_reference
{
	enum {value = sizeof(
            is_reference_helper2(
                is_reference_helper1(wrap<T>()))) == 1};
};
    
//////////////////////////////////////////////////////////////////////////
template <> struct is_reference<void>{enum {value = false};};

//////////////////////////////////////////////////////////////////////////
//  memmory manipulation
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
inline void noMemClear(void *_p, int size)
{
	char *p = (char *)_p;
	const char *e = p + size;
	for( ; p < e; p++ ){*p = 0;}
}

//////////////////////////////////////////////////////////////////////////
inline void noMemCopy(void *_d, const void *_s, int size)
{
	char *d = (char *)_d;
	const char *s = (const char *)_s;
	const char *e = s + size;
	for( ; s < e; d++, s++ ){*d = *s;}
}

//////////////////////////////////////////////////////////////////////////
//  binary stream manipulation
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
template <class Type>
Type noReadBin(std::istream &stream)
{
	Type value;
	stream.read((char*)&value,sizeof(Type));
	return(value);
}

//////////////////////////////////////////////////////////////////////
template <class Type>
std::istream& noReadBin(Type &value, std::istream &stream)
{	
	stream.read((char*)&value,sizeof(Type));
	return(stream);
}

//////////////////////////////////////////////////////////////////////
inline std::istream& noReadBin(void* value, unsigned int size, std::istream &stream)
{	
	stream.read((char*)value,size);
	return(stream);
}

//////////////////////////////////////////////////////////////////////
template <class Type>
Type noPeekBin(std::istream &stream)
{
	int pos = stream.tellg();
	Type value = noReadBin<Type>(stream);
	stream.seekg(pos);
	return(value);
}

//////////////////////////////////////////////////////////////////////
template <class Type>
std::ostream& noWriteBin(const Type &value,std::ostream &stream)
{	
	char* iter = ((char*)&value);
	char* end = iter+sizeof(Type);
	for (;iter<end;iter++) stream.put(*iter);
	return(stream);
}

//////////////////////////////////////////////////////////////////////
inline std::ostream& noWriteBin(const void* value,unsigned int size,std::ostream &stream)
{	
	char* iter = ((char*)value);
	char* end = iter+size;
	for (;iter<end;iter++) 
	{
		stream.put(*iter);
	}
	return(stream);
}

//////////////////////////////////////////////////////////////////////////
// endian
// Network order is big endian. 
// Host order is system specific exp: x86=>little, ppc=>big. 
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
inline bool noIsLittleEndian()
{
    const int t = 1;
    return(*((char*)(&t)) ? true : false);
}

//////////////////////////////////////////////////////////////////////////
template<class Type>
void noReverseBytes(Type& obj)
{
    unsigned char* ptr = (unsigned char*)( &obj );
    std::reverse(ptr, ptr + sizeof(Type));
}

//////////////////////////////////////////////////////////////////////////
template<class Type> void noHostToNetworkOrder(Type& obj) {if(noIsLittleEndian()) {noReverseBytes(obj);}}
template<class Type> void noNetworkToHostOrder(Type& obj) {if(noIsLittleEndian()) {noReverseBytes(obj);}}

#endif
